export = {}
/** 2. 联合类型Union Types(或 运算)*/
//联合类型表示一个值可以是几种类型之一。
//我们用竖线（ |）分隔每个类型
interface A {
  name: string;
  age: number;
}

interface B {
  name: string;
  grade: number;
}

// 只要c满足A或则B类型即可 (属性可以多 不能少)
const c: A | B = {
  name: 'c',
  grade: 100,
  // age: 123 //← 属性可以多 不能少

  //↓但不能多一个即不在A又不在B的属性
  // xyz: 'wf' //TS2322: Type '{ name: string; grade: number; xyz: string; }' is not assignable to type 'A | B'.
  // Object literal may only specify known properties, and 'xyz' does not exist in type 'A | B'.
};
// c.name //√
// c.grade //√

const c2: A | B = {
  name: 'c',
  grade: 100,
  age: 123 //← 属性可以多 不能少
};
//但是这样取值的时候就不像上面了, 取值的时候我们只能取出A和B公有的了
c2.name; //√
// c2.age //TS2339: Property 'age' does not exist on type 'A | B'.   Property 'age' does not exist on type 'B'.


//---

// function add(a:number|string, b:number|string) {
//   return a + b; // ts认为如果出现number+string的情况 是一种逻辑错误的情况 故报错
// }
// add(1, 2);
// add('1', '2');
// add(1, '2');

// ↓也是不行的 因为 泛型太泛了
// 我们虽然用extends限制了T的下线
// 但上线无法限制,即不能限制它可能还是什么 故会报错
// function add<T extends number|string>(a:T,b:T){
//   return a + b;
// }

function add(n1:number,n2:number):number
function add(n1:string,n2:string):string
function add(n1, n2) {
  return n1 + n2;
}

add(1, 2);
add('1', '2');
add(1, '2');
/*↑
TS2769: No overload matches this call.
Overload 1 of 2, '(n1: number, n2: number): number', gave the following error.
Argument of type '"2"' is not assignable to parameter of type 'number'.
Overload 2 of 2, '(n1: string, n2: string): string', gave the following error.
Argument of type '1' is not assignable to parameter of type 'string'.*/


/** 如果联合类型的成员都是接口,则当无法确定一个联合类型具体为什么类型的时候,只能访问它们的公有属性*/
interface Bird {
  fly();
  layEggs();
}

interface Fish {
  swim();
  layEggs();
}

function getSmallPet(): Fish | Bird {
  // ...
  return
}

let pet = getSmallPet();
pet.layEggs(); // okay
pet.swim();    // errors
